iT邦幫忙

2022 iThome 鐵人賽

DAY 5
0
Web 3

Smart-Contract Language: Move系列 第 11

Day 11 Advanced Topics: Global Storage Structures / Operators

  • 分享至 

  • xImage
  •  

Global Storage

Move 透過讀取和寫入 Tree 來實現持久的全局儲存,程式無法訪問此 Tree 之外的文件系統、網路或任意數據。

example

struct GlobalStorage {
  resources: Map<(address, ResourceType), ResourceValue>
  modules: Map<(address, ModuleName), ModuleBytecode>
}

全局儲存是由 address 和 Tree 互相搭配,如上面範例,每個地址都可以儲存資源數據值和模塊代碼值。

Operators 操作

Move 可以使用下面五個指令在全局儲存中創建、刪除、和更新資源

  • move_to<T>(&signer,T)
    • 發表 T 於 signer.address
  • move_from<T>(address): T
    • 刪除 T 並 address 返回
  • borrow_global_mut<T>(address): &mut T
    • 返回對 T 儲存在下面的可變引用 address
  • borrow_global<T>(address): &T
    • 返回對 T 儲存在下面的不可變引用 address
  • exists<T>(address): bool
    • 如果 T 儲存在 address 下,則返回 true

還記得上一篇提到的 type 四種能力的 key 能力,上述這些指令中都必須是具有 key 能力的類型。且每個類型 (T) 必須在當前 Module 中聲明,確保資源只能通做其定義 Module 的公開 API 進行操作。

對資源的引用

本地引用和全局引用有個重要的區別,函數不能返回指向全局儲存的引用:

struct R has key { f: u64 }
// will not compile
fun ret_direct_resource_ref_bad(a: address): &R {
    borrow_global<R>(a) /// error
}
// also will not compile
fun ret_resource_field_ref_bad(a: address): &u64 {
    &borrow_global<R>(a).f /// error
}

Move 必須強制執行此限制以保證不存在對全局儲存的懸空引用,我們後面也會介紹到。

具有泛型的全局儲存運算符

全局存儲操作可以應用於具有實例化和未實例化的泛型類型參數的泛型資源:

通過在運行時選擇的類型參數對全局存儲進行索引的能力是一種強大的移動特性,稱為存儲多態性。我們在後面 Generic 章節會詳細介紹 T。

struct Container<T> has key { t: T }

// Publish a Container storing a type T of the caller's choosing
fun publish_generic_container<T>(account: &signer, t: T) {
    move_to<Container<T>>(account, Container { t })
}

/// Publish a container storing a u64
fun publish_instantiated_generic_container(account: &signer, t: u64) {
    move_to<Container<u64>>(account, Container { t })
}

example

下面的範例程式碼練習了五個全局儲存運算符中的每一個,該 Module 公開的 API 允許:

  • 任何人都可以在其帳戶下發布 Counter 資源
  • 任何人都可以檢查 Counter 下是否存在任何地址
  • 任何人都可以讀取或增加任何地址下的 Counter 資源
  • 任何帳戶都可以存儲 Counter 資源以將其重置為零
  • 任何帳戶都可以存儲 Counter 資源以將其刪除
address 0x42 {
module Counter {
    use Std::Signer;

    /// Resource that wraps an integer counter
    struct Counter has key { i: u64 }

    /// Publish a `Counter` resource with value `i` under the given `account`
    public fun publish(account: &signer, i: u64) {
      move_to(account, Counter { i })
    }

    /// Read the value in the `Counter` resource stored at `addr`
    public fun get_count(addr: address): u64 acquires Counter {
        borrow_global<Counter>(addr).i
    }

    /// Increment the value of `addr`'s `Counter` resource
    public fun increment(addr: address) acquires Counter {
        let c_ref = &mut borrow_global_mut<Counter>(addr).i;
        *c_ref = *c_ref + 1
    }

    /// Reset the value of `account`'s `Counter` to 0
    public fun reset(account: &signer) acquires Counter {
        let c_ref = &mut borrow_global_mut<Counter>(Signer::address_of(account)).i;
        *c_ref = 0
    }

    /// Delete the `Counter` resource under `account` and return its value
    public fun delete(account: &signer): u64 acquires Counter {
        // remove the Counter resource
        let c = move_from<Counter>(Signer::address_of(account));
        let Counter { i } = c;
        i
    }

    /// Return `true` if `addr` contains a `Counter` resource
    public fun isExists(addr: address): bool {
        exists<Counter>(addr)
    }
}
}

Global 資源參考安全

Move 禁止返回全局引用,並且需要 acquires 註解來防止懸空引用。我們在上面的例子已經看過

 public fun delete(account: &signer): u64 acquires Counter {
        // remove the Counter resource
        let c = move_from<Counter>(Signer::address_of(account));
        let Counter { i } = c;
        i
    }

本篇介紹了前面幾篇一直提到的全局儲存,以及上篇的 key 能力。讓我們 Move to Day12

相關資料

Tree: https://en.wikipedia.org/wiki/Tree_(graph_theory)


上一篇
Day 10 Types with Abilities
下一篇
Day 12 Advanced Topics: References
系列文
Smart-Contract Language: Move30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言